/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
      
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.


See LICENSE and AUTHORS for more information.
*/

#include "xmppconnection.h"
#include "qxmpp/QXmppMessage.h"
#include "qxmpp/QXmppRoster.h"
#include "qxmpp/QXmppRosterIq.h"
#include <QSqlDatabase>
#include <QSqlQuery>

/**
  constructor
  */
XmppConnection::XmppConnection(int uid,int accid, QObject *parent)
    : QXmppClient(parent)
{
    bool check = connect(this, SIGNAL(messageReceived(const QXmppMessage&)),
        SLOT(messageReceived(const QXmppMessage&)));
    Q_ASSERT(check);

    check = connect(&this->getRoster(),
                    SIGNAL(presenceChanged(const QString&, const QString&)),
                    SLOT(presenceChanged(const QString&, const QString&)));
    Q_ASSERT(check);

    check = connect(this,SIGNAL(iqReceived(QXmppIq)),this,SLOT(iqReceived(QXmppIq)));
    Q_ASSERT(check);
    
    check = connect(this,SIGNAL(rosterReceived()),this,SLOT(parseRoster()));

    Q_UNUSED(check);

    this->uid = uid;
    this->accid = accid;
}

/**
* @brief send XEP-0085 state notification
*/
void XmppConnection::sendState(QString bareJid, QString state)
{
    QStringList resources = getRoster().getResources(bareJid);
    for(int i = 0; i < resources.size(); ++i)
    {
        QXmppMessage qxm = QXmppMessage("", bareJid + "/" + resources.at(i), "");
        if(state == "composing")
	  qxm.setState(QXmppMessage::Composing);
	else if( state == "paused")
	{
	 qxm.setState(QXmppMessage::Paused); 
	}
	else {
	  qxm.setState(QXmppMessage::Active);
	}
        sendPacket(qxm);
    }
 
}
/**
* @brief forward roster to the client on rosterReceived()
*/
void XmppConnection::parseRoster() 
{
    QSqlDatabase conn = QSqlDatabase::database("core");
    if(!conn.open())
    {
        qDebug() << "the core database could not be opened in xmppconnection";
        Q_ASSERT(false);
    }

    QXmppRoster& roster = getRoster();
    QStringList jids = roster.getRosterBareJids();
    for (int i=0;i<jids.size();i++)
    {
        QXmppRoster::QXmppRosterEntry re = roster.getRosterEntry(jids.at(i));  
        QSqlQuery q(conn);
        q.prepare(QString("SELECT jid,name,subscription,accid,grp FROM buddies_%1 WHERE accid=:accid AND jid=:jid").arg(this->uid));
        q.bindValue(":accid",this->accid);
        q.bindValue(":jid",jids.at(i));
        q.exec();
        if(q.first())
        {
            if( q.value(0).toString() == re.bareJid() && 
                q.value(1).toString() == re.name() && 
                q.value(2).toInt() == (int) re.subscriptionType() )
            {
                // If we have the exact information in the database already,
                // we skip this buddy and continue with the next one
                continue;
            }

            q.prepare(QString("UPDATE buddies_%1 SET name = :name, subscription = :sub, grp = :grp WHERE jid = :jid AND accid = :accid ").arg(this->uid));
            q.bindValue(":jid",re.bareJid());
            q.bindValue(":name",re.name());
            q.bindValue(":sub",(int) re.subscriptionType());
            q.bindValue(":accid",this->accid);
            q.bindValue(":grp",re.groups().toList().at(0));
            q.exec();
        }
        q.prepare(QString("INSERT INTO buddies_%1 (jid,name,subscription,accid,grp) VALUES (:jid,:name,:sub,:accid,:grp) ").arg(this->uid));
        q.bindValue(":jid",re.bareJid());
        q.bindValue(":name",re.name());
        q.bindValue(":sub",(int) re.subscriptionType());
        q.bindValue(":accid",this->accid);
        q.bindValue(":grp",re.groups().toList().at(0));
        q.exec();
    }
}

/**
    Forward the message to SslClient
    */
void XmppConnection::messageReceived(const QXmppMessage& message)
{
    QString from = message.from();
    from = from.split("/").value(0);
    QString msg = message.body();
    qDebug() << "msg state:" << message.state() << " from " << from;
    emit(stateChanged(from,message.state(),this->accid,this->uid));
    emit(msgRecv(from,this->getConfiguration().jidBare(),msg,this->accid,this->uid));
}

void XmppConnection::presenceChanged(const QString& bareJid, const QString& resource)
{
   QXmppPresence qxp = this->getRoster().getPresence(bareJid,resource);
   emit(statusChanged(qxp.getStatus().getTypeStr(),qxp.getStatus().getStatusText(),QString(bareJid),QString(resource),this->accid,this->uid));
}


void XmppConnection::iqReceived(const QXmppIq& iq)
{
    return;
}


/**
* @brief Utility function to send message to all the resources associated with the
* specified bareJid.
*
* @param bareJid bareJid of the receiving entity
* @param message Message string to be sent.
*/
void XmppConnection::sendMessageActive(const QString& bareJid, const QString& message)
{
    QStringList resources = getRoster().getResources(bareJid);
    for(int i = 0; i < resources.size(); ++i)
    {
        QXmppMessage qxm = QXmppMessage("", bareJid + "/" + resources.at(i), message); 
        // This enables the feature XEP-0085 to be send with state 1 beeing <active />
        qxm.setState(QXmppMessage::Active);
        sendPacket(qxm);
    }
}
